package www.superbytecode.com.configuation;

import org.mybatis.generator.api.CommentGenerator;
import org.mybatis.generator.api.IntrospectedColumn;
import org.mybatis.generator.api.IntrospectedTable;
import org.mybatis.generator.api.dom.java.*;
import org.mybatis.generator.api.dom.xml.XmlElement;
import org.mybatis.generator.internal.util.StringUtility;
import www.superbytecode.com.constant.Properites;
import www.superbytecode.com.util.DateUtil;
import www.superbytecode.com.util.TextUtil;

import java.util.Properties;
import java.util.Set;

/**
 * All rights Reserved, Designed By www.super-bytecode.com
 *
 * @ProjectName superbytecode-builder
 * @Package www.superbytecode.com.configuation
 * @ClassName DBCommentGenerator
 * @Description 此插件使用数据库表中列的注释来生成Java Model中属性的注释
 * @Author [Lance Ting]
 * @Date 2020/7/14 20:37
 * @Version V1.0
 * @Copyright: 2020 www.super-bytecode.com Inc. All rights reserved.
 * @TODO：本文件Lance Ting所作, 如果转载或使用请标明具体出处!
 **/
public class DBCommentGenerator implements CommentGenerator {

    final String projectName = Properites.PROJECT_NAME;
    final String projectVersion = Properites.PROJECT_VSERION;

    private Properties properties;
    private boolean columnRemarks;
    private boolean isAnnotations;

    public DBCommentGenerator() {
        super();
        properties = new Properties();
    }

    /**
     * Adds properties for this instance from any properties configured in the
     * CommentGenerator configuration.
     *
     * <p>This method will be called before any of the other methods.
     *
     * @param properties All properties from the configuration
     */
    @Override
    public void addConfigurationProperties(Properties properties) {
        this.properties.putAll(properties);
        columnRemarks = TextUtil.isTrue(properties.getProperty("columnRemarks"));
        isAnnotations = TextUtil.isTrue(properties.getProperty("annotations"));
    }

    /**
     * This method should add a Javadoc comment to the specified field. The field is related to the
     * specified table and is used to hold the value of the specified column.
     *
     * <p><b>Important:</b> This method should add a the nonstandard JavaDoc tag "@mbg.generated" to
     * the comment. Without this tag, the Eclipse based Java merge feature will fail.
     *
     * @param field              the field
     * @param introspectedTable  the introspected table
     * @param introspectedColumn
     */
    @Override
    public void addFieldComment(Field field, IntrospectedTable introspectedTable, IntrospectedColumn introspectedColumn) {
        if (StringUtility.stringHasValue(introspectedColumn.getRemarks())) {
            field.addJavaDocLine("/**");
            StringBuilder sb = new StringBuilder();
            sb.append(" * ");
            sb.append(introspectedColumn.getRemarks());
            field.addJavaDocLine(sb.toString());
            field.addJavaDocLine(" */");
        }
        if (!isAnnotations) {
            return;
        }
        boolean isId = false;
        for (IntrospectedColumn column : introspectedTable.getPrimaryKeyColumns()) {
            if (introspectedColumn == column) {
                isId = true;
                field.addAnnotation("@Id");
                field.addAnnotation("@GeneratedValue");
                break;
            }
        }
        if (!introspectedColumn.isNullable() && !isId) {
            field.addAnnotation("@NotEmpty");
        }
        if (introspectedColumn.isIdentity()) {
            if (introspectedTable.getTableConfiguration().getGeneratedKey().getRuntimeSqlStatement().equals("JDBC")) {
                field.addAnnotation("@GeneratedValue(generator = \"JDBC\")");
            } else {
                field.addAnnotation("@GeneratedValue(strategy = GenerationType.IDENTITY)");
            }
        } else if (introspectedColumn.isSequenceColumn()) {
            field.addAnnotation("@SequenceGenerator(name=\"\",sequenceName=\"" + introspectedTable.getTableConfiguration().getGeneratedKey().getRuntimeSqlStatement() + "\")");
        }
    }

    /**
     * Adds the field comment.
     *
     * @param field             the field
     * @param introspectedTable
     */
    @Override
    public void addFieldComment(Field field, IntrospectedTable introspectedTable) {

    }

    /**
     * Adds a comment for a model class.  The Java code merger should
     * be notified not to delete the entire class in case any manual
     * changes have been made.  So this method will always use the
     * "do not delete" annotation.
     * 类注释
     * <p>Because of difficulties with the Java file merger, the default implementation
     * of this method should NOT add comments.  Comments should only be added if
     * specifically requested by the user (for example, by enabling table remark comments).
     *
     * @param topLevelClass     the top level class
     * @param introspectedTable
     */
    @Override
    public void addModelClassComment(TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {
        String currentDate = DateUtil.getCurrentDateText();// 当前日期
        String currentYear = String.valueOf(DateUtil.getCurrentYear());// 当前年份
        String tableName = introspectedTable.getFullyQualifiedTableNameAtRuntime();//表名
        String packageName = topLevelClass.getType().getPackageName(); //包名
        String classShortName = topLevelClass.getType().getShortName();// 类名

        topLevelClass.addJavaDocLine("/**");
        topLevelClass.addJavaDocLine("* All rights Reserved, Designed By www.super-bytecode.com");
        topLevelClass.addJavaDocLine("* ");
        topLevelClass.addJavaDocLine("* @ProjectName " + projectName);
        topLevelClass.addJavaDocLine("* @Package " + packageName);
        topLevelClass.addJavaDocLine("* @ClassName " + classShortName);
        topLevelClass.addJavaDocLine("* @Description[数据库表 " + tableName + "]");
        topLevelClass.addJavaDocLine("* @Author [Lance Ting]");
        topLevelClass.addJavaDocLine("* @Date " + currentDate + "");
        topLevelClass.addJavaDocLine("* @Version " + projectVersion);
        topLevelClass.addJavaDocLine("* @Copyright: " + currentYear + " www.super-bytecode.com Inc. All rights reserved.");
        topLevelClass.addJavaDocLine("* @see 注意：本文件Lance Ting所作,如果转载或使用请标明具体出处!");
        topLevelClass.addJavaDocLine(" **/");

        // 类是否加注释
        if (isAnnotations) {
            topLevelClass.addAnnotation("@Talbe(name=\"" + tableName + "\")");
        }
    }

    /**
     * Adds the inner class comment.
     *
     * @param innerClass        the inner class
     * @param introspectedTable
     */
    @Override
    public void addClassComment(InnerClass innerClass, IntrospectedTable introspectedTable) {
        //
    }

    /**
     * Adds the inner class comment.
     *
     * @param innerClass        the inner class
     * @param introspectedTable the introspected table
     * @param markAsDoNotDelete
     */
    @Override
    public void addClassComment(InnerClass innerClass, IntrospectedTable introspectedTable, boolean markAsDoNotDelete) {
        innerClass.addJavaDocLine("/**"); //$NON-NLS-1$
        innerClass.addJavaDocLine(" */"); //$NON-NLS-1$
    }

    /**
     * Adds the enum comment.
     *
     * @param innerEnum         the inner enum
     * @param introspectedTable
     */
    @Override
    public void addEnumComment(InnerEnum innerEnum, IntrospectedTable introspectedTable) {

    }

    /**
     * Adds the getter comment.
     *
     * @param method             the method
     * @param introspectedTable  the introspected table
     * @param introspectedColumn
     */
    @Override
    public void addGetterComment(Method method, IntrospectedTable introspectedTable, IntrospectedColumn introspectedColumn) {

    }

    /**
     * Adds the setter comment.
     *
     * @param method             the method
     * @param introspectedTable  the introspected table
     * @param introspectedColumn
     */
    @Override
    public void addSetterComment(Method method, IntrospectedTable introspectedTable, IntrospectedColumn introspectedColumn) {
    }

    /**
     * Adds the general method comment.
     *
     * @param method            the method
     * @param introspectedTable
     */
    @Override
    public void addGeneralMethodComment(Method method, IntrospectedTable introspectedTable) {
    }

    /**
     * This method is called to add a file level comment to a generated java file. This method
     * could be used to add a general file comment (such as a copyright notice). However, note
     * that the Java file merge function in Eclipse does not deal with this comment. If you run
     * the generator repeatedly, you will only retain the comment from the initial run.
     *
     * <p>The default implementation does nothing.
     *
     * @param compilationUnit the compilation unit
     */
    @Override
    public void addJavaFileComment(CompilationUnit compilationUnit) {
        // add no file level comments by default
        if (!isAnnotations) {
            return;
        }
        compilationUnit.addImportedType(new FullyQualifiedJavaType("javax.persistence.Table"));
        compilationUnit.addImportedType(new FullyQualifiedJavaType("javax.persistence.Id"));
        compilationUnit.addImportedType(new FullyQualifiedJavaType("javax.persistence.Column"));
        compilationUnit.addImportedType(new FullyQualifiedJavaType("javax.persistence.GeneratedValue"));
        compilationUnit.addImportedType(new FullyQualifiedJavaType("org.hibernate.validator.constraints.NotEmpty"));
    }

    /**
     * This method should add a suitable comment as a child element of the specified xmlElement to warn users that the
     * element was generated and is subject to regeneration.
     *
     * @param xmlElement the xml element
     */
    @Override
    public void addComment(XmlElement xmlElement) {
    }

    /**
     * This method is called to add a comment as the first child of the root element. This method
     * could be used to add a general file comment (such as a copyright notice). However, note
     * that the XML file merge function does not deal with this comment. If you run the generator
     * repeatedly, you will only retain the comment from the initial run.
     *
     * <p>The default implementation does nothing.
     *
     * @param rootElement the root element
     */
    @Override
    public void addRootComment(XmlElement rootElement) {
        return;
    }

    /**
     * Adds a @Generated annotation to a method.
     *
     * @param method            the method
     * @param introspectedTable the introspected table
     * @param imports           the comment generator may add a required imported type to this list
     * @since 1.3.6
     */
    @Override
    public void addGeneralMethodAnnotation(Method method, IntrospectedTable introspectedTable, Set<FullyQualifiedJavaType> imports) {
    }

    /**
     * Adds a @Generated annotation to a method.
     *
     * @param method             the method
     * @param introspectedTable  the introspected table
     * @param introspectedColumn thr introspected column
     * @param imports            the comment generator may add a required imported type to this list
     * @since 1.3.6
     */
    @Override
    public void addGeneralMethodAnnotation(Method method, IntrospectedTable introspectedTable, IntrospectedColumn introspectedColumn, Set<FullyQualifiedJavaType> imports) {
    }

    /**
     * Adds a @Generated annotation to a field.
     *
     * @param field             the field
     * @param introspectedTable the introspected table
     * @param imports           the comment generator may add a required imported type to this list
     * @since 1.3.6
     */
    @Override
    public void addFieldAnnotation(Field field, IntrospectedTable introspectedTable, Set<FullyQualifiedJavaType> imports) {
    }

    /**
     * Adds a @Generated annotation to a field.
     *
     * @param field              the field
     * @param introspectedTable  the introspected table
     * @param introspectedColumn the introspected column
     * @param imports            the comment generator may add a required imported type to this list
     * @since 1.3.6
     */
    @Override
    public void addFieldAnnotation(Field field, IntrospectedTable introspectedTable, IntrospectedColumn introspectedColumn, Set<FullyQualifiedJavaType> imports) {
    }

    /**
     * Adds a @Generated annotation to a class.
     *
     * @param innerClass        the class
     * @param introspectedTable the introspected table
     * @param imports           the comment generator may add a required imported type to this list
     * @since 1.3.6
     */
    @Override
    public void addClassAnnotation(InnerClass innerClass, IntrospectedTable introspectedTable, Set<FullyQualifiedJavaType> imports) {
    }
}